动态数组. 其模板类中包含了三根指针, 分别指向begin、end和end of storage. vector的大小size = end - begin, 其容量cap = end of storage - begin.
1 2 3 4 5
struct _Vector_impl_data { pointer _M_start; // begin pointer _M_finish; // end pointer _M_end_of_storage; // end of storage }
我们来看一个标准库中的使用场景:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// [23.2.4.2] capacity /** Returns the number of elements in the %vector. */ size_type size()const _GLIBCXX_NOEXCEPT { returnsize_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
/** * Returns the total number of elements that the %vector can * hold before needing to allocate more memory. */ size_type capacity()const _GLIBCXX_NOEXCEPT { returnsize_type(this->_M_impl._M_end_of_storage - this->_M_impl._M_start); }
/** * @brief Add data to the end of the %vector. * @param __x Data to be added. * * This is a typical stack operation. The function creates an * element at the end of the %vector and assigns the given data * to it. Due to the nature of a %vector this operation can be * done in constant time if the %vector has preallocated space * available. */ void push_back(const value_type& __x) { if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) { _GLIBCXX_ASAN_ANNOTATE_GROW(1); _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, __x); ++this->_M_impl._M_finish; _GLIBCXX_ASAN_ANNOTATE_GREW(1); } else _M_realloc_insert(end(), __x); }
/** * @brief A list::iterator. * * All the functions are op overloads. */ template<typename _Tp> struct _List_iterator { typedef _List_iterator<_Tp> _Self; typedef _List_node<_Tp> _Node;
// Must downcast from _List_node_base to _List_node to get to value. reference operator*() const _GLIBCXX_NOEXCEPT { return *static_cast<_Node*>(_M_node)->_M_valptr(); }
template<typename _Tp, typename _Alloc = std::allocator<_Tp> > class list : protected _List_base<_Tp, _Alloc> { using _Base::_M_impl; using _Base::_M_put_node; using _Base::_M_get_node; using _Base::_M_get_Node_allocator;
// _M_node 指向 end 结点, 其next指向 begin iterator begin() _GLIBCXX_NOEXCEPT { returniterator(this->_M_impl._M_node._M_next); }
/** * @brief Move construct string. * @param __str Source string. * * The newly-created string contains the exact contents of @a __str. * @a __str is a valid, but unspecified string. **/ basic_string(basic_string&& __str) noexcept : _M_dataplus(_M_local_data(), std::move(__str._M_get_allocator())) { if (__str._M_is_local()) { traits_type::copy(_M_local_buf, __str._M_local_buf, _S_local_capacity + 1); } else { _M_data(__str._M_data()); _M_capacity(__str._M_allocated_capacity); }
// Must use _M_length() here not _M_set_length() because // basic_stringbuf relies on writing into unallocated capacity so // we mess up the contents if we put a '\0' in the string. _M_length(__str.length()); __str._M_data(__str._M_local_data()); __str._M_set_length(0); }